﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.DirectShow.Filters;
using System.Windows.Media.DirectShow.Vorbis;
using System.Linq;
using System.IO;

namespace System.Windows.Media.DirectShow.Ogg
{
    public class OggVorbisDecoder : MediaSourceAsync
    {


        private OggVorbisOutputPin outputPin;
        private OggFileStream physicalOggStream;
        private VorbisStream vorbisStream;

        public OggVorbisDecoder()
        {

        }

        public override string Name
        {
            get { return "Ogg audio decoder"; }
        }

        protected override void RunInternal(TimeSpan start)
        {
            base.RunInternal(start);

            if (this.outputPin.ConnectedPin == null) return;

            // Restart file reading
            this.CurrentStream.Seek(0, SeekOrigin.Begin);
            this.PrepareVorbisStream();

            this.QueueWork(SendPackets);
        }

        protected override void StopInternal()
        {
            base.StopInternal();
        }

        private void SendPackets(object s)
        {
            byte[] data = new byte[this.outputPin.Allocator.Properties.BufferSize];
            int l;
            while (this.State != FilterState.Stopped && (l = vorbisStream.ReadPcm(data)) > 0)
            {
                this.outputPin.ProcessStream(new MemoryStream(data, 0, l), 0, l);
            }

            if (this.State != FilterState.Stopped)
            {
                this.outputPin.Flush();
                this.outputPin.DeliverEndOfStream();
            }
        }

        protected override void OnStreamAvailable(System.IO.Stream stream)
        {
            base.OnStreamAvailable(stream);

            this.PrepareVorbisStream();

            WaveFormatExtensible format = new WaveFormatExtensible();
            format.Channels = (short)vorbisStream.Channels;
            format.BitsPerSample = 16;
            format.FormatTag = 1; // PCM
            format.SamplesPerSec = vorbisStream.SampleRate;
            format.BlockAlign = (short)(2 * vorbisStream.Channels);
            format.AverageBytesPerSecond = format.Channels * 2 * format.SamplesPerSec;

            AMMediaType mt = new AMMediaType
            {
                MajorType = MediaMajorTypes.Audio,
                SubType = MediaSubTypes.PCM,
                FixedSizeSamples = false,
                SampleSize = format.SamplesPerSec,
                Format = format
            };

            outputPin = new OggVorbisOutputPin(this, mt);
            this.Pins.Clear();
            this.Pins.Add(outputPin);
        }

        private void PrepareVorbisStream()
        {
            physicalOggStream = new OggFileStream(this.CurrentStream);

            // TODO: only first stream supported
            vorbisStream = new VorbisStream(physicalOggStream.LogicalStreams.Cast<ILogicalOggStream>().FirstOrDefault());
        }
    }
}
